﻿//参考网址
//http://bitoftech.net/2014/07/16/enable-oauth-refresh-tokens-angularjs-app-using-asp-net-web-api-2-owin/
using System;
using System.Security.Claims;
using System.Security.Principal;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Owin.Security.Infrastructure;
using Sharp.DataTransferObject;
using Sharp.Infrastructure.IoC;
using Sharp.Infrastructure.WebApiClient;
using Sharp.ServiceContracts;

namespace Sharp.Portal.Mvc.OAuth.Sharp.Server
{
    public class SharpAuthenticationTokenProvider : AuthenticationTokenProvider
    {
        public string TokenType
        {
            get;
            set;
        }

        public TimeSpan ExpireTimeSpan { get; set; }

        public bool RemoveWhenReceive = false;

        /// <summary>
        /// 重新生成Token条件
        /// </summary>
        public Predicate<AuthorizationDTO> OldTokenRemovetPredicate = data => true;

        /// <summary>
        /// 保留Token条件
        /// </summary>
        public Predicate<AuthorizationDTO> TokenKeepingPredicate = data => false;


        private int GetExpiryMinutes()
        {
            if (ExpireTimeSpan != null)
            {
                return (int)ExpireTimeSpan.TotalMinutes;
            }
            return 1;
        }
        /// <summary>
        /// 生成Token
        /// </summary>
        /// <param name="context"></param>
        public override void Create(AuthenticationTokenCreateContext context)
        {
            var startDate = DateTime.UtcNow;
            var endDate = DateTime.UtcNow.AddMinutes(GetExpiryMinutes());
            AuthorizationDTO grantData = new AuthorizationDTO
            {
                GrantType = context.OwinContext.Get<string>("as:grant_type"),
                ResponseType = context.OwinContext.Get<string>("as:response_type"),
                TokenType = TokenType,
                UserId = context.OwinContext.Get<string>("as:user_id"),
                UserName = context.OwinContext.Get<string>("as:user_name"),
                ClientId = context.OwinContext.Get<string>("as:client_id"),
                IssuedUtc = startDate,
                ExpiresUtc = endDate,
                //RoleScope = GetIdentityRole(context.Ticket.Identity)
            };
            if (TokenKeepingPredicate(grantData))
            {
                using (var proxy = new WebApiClientServiceProxy<IOAuthService>())
                {
                    grantData = proxy.Channel.GetTicketValue(grantData.Token);
                    if (grantData != null)
                    {
                        context.SetToken(grantData.Token);
                        return;
                    }
                }

            }
            if (OldTokenRemovetPredicate(grantData))
            {
                using (var proxy = new WebApiClientServiceProxy<IOAuthService>())
                {
                    proxy.Channel.RemoveOldTicket(grantData);
                }
            }
            var tokenValue = Convert.ToBase64String(Encoding.UTF8.GetBytes(Guid.NewGuid().ToString("n"))).TrimEnd('=').Replace('+', '-').Replace('/', '_');


            context.Ticket.Properties.IssuedUtc = startDate;
            context.Ticket.Properties.ExpiresUtc = endDate;
            grantData.Ticket = context.SerializeTicket();
            grantData.Token = tokenValue;

            using (var proxy = new WebApiClientServiceProxy<IOAuthService>())
            {
                proxy.Channel.SetTicketValue(grantData);
            }
            context.SetToken(tokenValue);
        }

        /// <summary>
        /// 接收Token
        /// </summary>
        /// <param name="context"></param>
        public override void Receive(AuthenticationTokenReceiveContext context)
        {
            AuthorizationDTO grantData = new AuthorizationDTO()
            {
                Token = context.Token
            };
            if (RemoveWhenReceive)
            {
                using (var proxy = new WebApiClientServiceProxy<IOAuthService>())
                {
                    grantData = proxy.Channel.GetTicketValue(grantData.Token);
                    context.DeserializeTicket(grantData.Ticket);
                }
            }
            else
            {
                using (var proxy = new WebApiClientServiceProxy<IOAuthService>())
                {
                    grantData = proxy.Channel.GetTicketValue(grantData.Token);
                    if (grantData == null)
                        throw new ArgumentNullException("Token不存在。");

                    context.DeserializeTicket(grantData.Ticket);
                }
            }
            context.OwinContext.Set("as:user_id", grantData.UserId);
            context.OwinContext.Set("as:user_name", grantData.UserName);
            context.OwinContext.Set("as:client_id", grantData.ClientId);
        }

        private static string GetIdentityRole(IIdentity identity)
        {
            ClaimsIdentity identity2 = identity as ClaimsIdentity;
            if (identity2 != null)
            {
                return identity2.FindFirst(identity2.RoleClaimType).Value;
            }
            return null;
        }

    }
}